package com.mhxy.util;

import cn.hutool.json.JSONUtil;
import com.mhxy.handler.ConfigHandler;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.ptr.IntByReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 获取HWND列表
 */
@Slf4j
public class HwndUtil {

    private static Logger LOG = LoggerFactory.getLogger(HwndUtil.class);

    public static List<HWND> hwnds = new ArrayList<>();

    public static Map<String, HwndEntity> hwndsMap = new TreeMap<>();
    // processId, HWND
    public static Map<Integer, HWND> loginHwndsMap = new TreeMap<>();

    public static Map<String, HWND> selectHwndsMap = new TreeMap<>();

    public static String name = "";
    public static String loginHwndName = "登录 [#]";

    @Data
    @AllArgsConstructor
    public static class HwndEntity {
        private HWND hwnd;
        // 进程ID
        private int processId;
    }

    /**
     * 获取启动的hwnd
     *
     * @return
     */
    public static Map<String, HwndEntity> getStartHwnds() {
        if (hwndsMap.size() > 0) {
//            LOG.info("选择启动部分句柄！句柄名字{}", JSONUtil.toJsonStr(hwndsMap.keySet()));
            return hwndsMap;
        }
        return loadAllGameHwnd(ConfigHandler.getBoxNames());
    }

    // [#] [MyGame1] MyPCLauncher_x64r [#]
    public static HWND getMyPCLauncher(String boxName) {
        hwnds.clear();
        String text = "["+boxName + "] MyPCLauncher_x64r";
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProc2(), null);
        if (result) {
            // 遍历收集到的句柄并获取窗口信息
            for (HWND hwnd : hwnds) {
                char[] buffer = new char[256];
                User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
                String windowText = Native.toString(buffer).trim();
//                System.out.println("Window Text: " + windowText);
                // Window Text: [#] [MyGame3] 梦幻西游：时空 [#], Class Name: Sandbox:MyGame3:VnHTEzcosm3KYTVgG4EZ3Sj
                // Window Text: [#] [MyGame1] MyPCLauncher_x64r [#], Class Name: Sandbox:MyGame1:MyPCLauncher_x64r
                if(windowText.contains("梦幻西游：时空")) {
                    System.out.println("Window Text: " + windowText);
                    return hwnd;
                }
                if (windowText.contains(text)) {
                    return hwnd;
                }
            }
        } else {
            System.err.println("EnumWindows failed.");
        }
        return null;
    }

    /**
     * 获取登录窗口句柄
     */
    public static HWND getLoginHwnd(int processId) {
        // [#] [MyGame1] 登录 [#]
        //使用对象指针，回调，
        Pointer pointer = Pointer.createConstant(0);
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProcByLogin(), pointer);
        if (!result) {
            LOG.error("查找HwndMap失败,找到{}个", loginHwndsMap.size());
            return null;
        }
        LOG.info("成功找到HwndMap,找到{}个", loginHwndsMap.size());
        return loginHwndsMap.get(processId);
    }

    /**
     * 根据启动BoxName按循序加载游戏窗口句柄
     */
    public static Map<String, HwndEntity> loadAllGameHwnd(List<String> boxNames) {
        for (String boxName : boxNames) {
            loadPcGameHwndByBoxName(boxName);
        }
        loginHwndsMap.keySet().forEach(key -> log.info("加载游戏窗口句柄: {}", key));
        return hwndsMap;
    }

    /**
     * 加载游戏窗口句柄
     */
    public static void loadPcGameHwndByBoxName(String boxName) {
        hwnds.clear();
        String text = "["+boxName+"] 梦幻西游：时空";
        List<HwndEntity> hwndEntities = new ArrayList<>();
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProc2(), null);
        if (result) {
            // 遍历收集到的句柄并获取窗口信息
            for (HWND hwnd : hwnds) {
                char[] buffer = new char[256];
                User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
                String windowText = Native.toString(buffer).trim();

                // 获取窗口的进程 ID
                IntByReference processId = new IntByReference();
                User32.INSTANCE.GetWindowThreadProcessId(hwnd, processId);

                if (windowText.contains(text)) {
                    System.out.println("Window Text: " + windowText + " processId: " + processId.getValue());
                    hwndEntities.add(new HwndEntity(hwnd, processId.getValue()));
                }
            }
        } else {
            System.err.println("EnumWindows failed.");
        }

        // 排序一下，以免错乱
        List<HwndEntity> sortedList = hwndEntities.stream().sorted((h1,h2) -> Integer.compare(h1.getProcessId(), h2.getProcessId())).collect(Collectors.toList());
        int number = 1;
        for (HwndEntity hwndEntity : sortedList) {
            String hwndName = boxName + "-" + number;
            System.out.println("processId: " + hwndEntity.getProcessId() + " hwndName: " + hwndName);
            hwndsMap.put(hwndName, hwndEntity);
            number++;
        }
    }
    public static void loadPcGameHwnd() {
        hwnds.clear();
        String text = "梦幻西游：时空";
        List<HwndEntity> hwndEntities = new ArrayList<>();
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProc2(), null);
        if (result) {
            // 遍历收集到的句柄并获取窗口信息
            for (HWND hwnd : hwnds) {
                char[] buffer = new char[256];
                User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
                String windowText = Native.toString(buffer).trim();

                // 获取窗口的进程 ID
                IntByReference processId = new IntByReference();
                User32.INSTANCE.GetWindowThreadProcessId(hwnd, processId);

                if (windowText.contains(text)) {
                    System.out.println("Window Text: " + windowText + " processId: " + processId.getValue());
                    hwndEntities.add(new HwndEntity(hwnd, processId.getValue()));
                }
            }
        } else {
            System.err.println("EnumWindows failed.");
        }

        // 排序一下，以免错乱
        List<HwndEntity> sortedList = hwndEntities.stream().sorted((h1,h2) -> Integer.compare(h1.getProcessId(), h2.getProcessId())).collect(Collectors.toList());
        int number = 1;
        for (HwndEntity hwndEntity : sortedList) {
            String hwndName = "game-" + number;
            System.out.println("processId: " + hwndEntity.getProcessId() + " hwndName: " + hwndName);
            hwndsMap.put(hwndName, hwndEntity);
            number++;
        }
    }

    public static HWND getByName(String name) {
        hwnds.clear();
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProc2(), null);
        if (result) {
            int number = 1;
            // 遍历收集到的句柄并获取窗口信息
            for (HWND hwnd : hwnds) {
                char[] buffer = new char[256];
                User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
                String windowText = Native.toString(buffer).trim();
                if (windowText.contains(name)) {
                    System.out.println("Window Text: " + windowText);
                    return hwnd;
                }
            }
        } else {
            System.err.println("EnumWindows failed.");
        }
        return null;
    }

    public static List<String> listNames(String name) {
        hwnds.clear();
        List<String> returnList = new ArrayList<>();
        boolean result = User32.INSTANCE.EnumWindows(new WndEnumProc2(), null);
        if (result) {
            int number = 1;
            // 遍历收集到的句柄并获取窗口信息
            for (HWND hwnd : hwnds) {
                char[] buffer = new char[256];
                User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
                String windowText = Native.toString(buffer).trim();
                System.out.println("Window Text: " + windowText);
                if (windowText.contains(name)) {
                    returnList.add(windowText);
                }
            }
        } else {
            System.err.println("EnumWindows failed.");
        }
        return returnList;
    }

    public static String getHwndTitle(HWND hwnd) {
        char[] buffer = new char[256];
        User32.INSTANCE.GetWindowText(hwnd, buffer, buffer.length);
        return Native.toString(buffer).trim();
    }

    public static Integer getHwndProcessId(HWND hwnd) {
        IntByReference processId = new IntByReference();
        User32.INSTANCE.GetWindowThreadProcessId(hwnd, processId);
        return processId.getValue();
    }

    /**
     * 设置所有窗口的大小和位置
     */
    public static void setWindowPost() {
        loadPcGameHwnd();
        AtomicInteger x = new AtomicInteger(50);
        AtomicInteger i = new AtomicInteger(0);
        hwndsMap.keySet().forEach(k -> {
            HwndEntity hwndEntity = hwndsMap.get(k);
            i.getAndIncrement();
            if (i.get() % 2 != 0) {
                setWindowPos(hwndEntity.getHwnd(), x.get(), 50);
            } else {
                setWindowPos(hwndEntity.getHwnd(), x.get(), 660);
                x.set(x.get() + 780);
            }
        });

    }

    public static void setWindowPos(HWND hwnd, int x, int y) {
        // 激活句柄
        User32.INSTANCE.SetForegroundWindow(hwnd);

        WinDef.RECT rect = new WinDef.RECT();
        User32.INSTANCE.GetWindowRect(hwnd, rect);
        int height = rect.right - rect.left;
        int width = rect.bottom - rect.top;
        //  屏幕长1298,宽1007
        LOG.info("屏幕长{},宽{}", height, width);
        double scale = 0.6;
        int wHeight = 778;
        int wWidth = 608;
        // 重置长778,宽604
        User32.INSTANCE.SetWindowPos(hwnd, null, x, y, wHeight, wWidth, 0);
        LOG.info("重置长{},宽{}, 位置: x={}, y={}", wHeight, wWidth, x, y);
    }


}


class WndEnumProc2 implements WinUser.WNDENUMPROC {
    @Override
    public boolean callback(HWND hWnd, Pointer data) {
        HwndUtil.hwnds.add(hWnd);
        return true;
    }
}
class WndEnumProcByLogin implements WinUser.WNDENUMPROC {
    @Override
    public boolean callback(HWND hWnd, Pointer data) {
        String title = HwndUtil.getHwndTitle(hWnd);
        Integer processId = HwndUtil.getHwndProcessId(hWnd);
        if (title.contains(HwndUtil.loginHwndName)) {
            HwndUtil.loginHwndsMap.put(processId, hWnd);
        }
        return true;
    }
}


